const defaultRE = /\{\{((?:.|\r?\n)+?)\}\}/g
export const util = {
    compilerText(node,vm) {
        if(!node.expr){
            node.expr = node.textContent // 将节点原本的内容挂载节点的expr上 因为它可能是一个vue模板语法字符串 我们不止在当前编译中会使用到 可能会重复使用(比如给数据赋值时导致视图刷新,就要重新利用这个模板)
        }
        node.textContent = node.expr.replace(defaultRE, function (...args) {
            return util.getValue(vm, args[1]); // 有可能是这样的→{{school.name}} 那么返回的即是vm.school.name, 否则就是vm.x
        });
        /* 注意:
            如果textContent要被赋的值非字符串 就会先执行`.toString`↓↓
            document.querySelector('.test').textContent = [1, 2, 3];
        */
    },
    getValue(vm, expr) { // school.name
        const keys = expr.split('.');
        return keys.reduce((memo, current) => {
            memo = memo[current]; // memo = vm.school
            return memo;
        },vm);
    }
};

export function compiler(node, vm) {
    const childNodes = node.childNodes; // 一层
    [...childNodes].forEach(child => { // 1.元素 2.文本
        if(child.nodeType === 1) { // 元素
            compiler(child,vm); // 递归
        }else if (child.nodeType === 3){ // 文本
            util.compilerText(child, vm);
        }
    });
}

export function query(el){
    if (typeof el === 'string') {
        return document.querySelector(el);
    }
    // 说明直接传的就是一个dom元素↓
    return el;
}

let callbacks = [];
function flushCallbacks() {
    callbacks.forEach(cb => cb());
}
export function nextTick(cb) { // cb 就是 flushQueue
    callbacks.push(cb);

    // 要异步刷新这个callbacks(据统计,异步任务会比dom更新快慢一个数量级)
    let timerFunc = () => {
        flushCallbacks()
    };
    // 下面这一堆是为了兼容
    // 依次尝试以 promise mutationObserver setImmediate setTimeout 的顺序来执行
    if(Promise){ // ←微任务
        return Promise.resolve().then(timerFunc);
    }
    if(MutationObserver){ // ←微任务
        let observe = new MutationObserver(timerFunc);
        let textNode = document.createTextNode(1);
        observe.observe(textNode, {characterData: true});
        textNode.textContent=2;
        return;
    }
    if(setImmediate){ // ←宏任务
        return setImmediate(timerFunc)
    }
    //↓定时器是最慢的 能尽量提前就尽量提前执行
    setTimeout(timerFunc,0)
}